import { Group } from 'src/modules/group/entities/group.entity';
import { GroupPlayerScore as GroupPlayerScoreEntity } from 'src/modules/group-player-score/entities/group-player-score.entity';
import logger from 'src/common/utils/log';
import { MatchInfo } from 'src/modules/match/entities/match.entity';
import { GameInfoV2 } from 'src/modules/game/entities/game.entity.v2';

const initGroupPlayerScore = {
  winMatchCount: 0,
  loseMatchCount: 0,
  winGameCount: 0,
  loseGameCount: 0,
  winRallyCount: 0,
  loseRallyCount: 0,
  eliminationPosition: 0,
};

class GroupPlayerScore extends GroupPlayerScoreEntity {
  defeat?: Array<number>; // 击败对手的ID
}

export const matchScoreHelper = {
  // constructor(private readonly matchService: MatchService) {}

  getMatchScore(
    group: Group,
    type: 'single' | 'team',
  ): Array<GroupPlayerScore> {
    logger.info(
      `start getMatchScore type: ${type} groupId: ${group.id} matchInfos: ${group.matchInfos.length}`,
    );
    const playerScoreInfo = group.matchInfos.reduce(
      (total, match): { [playerId: number]: GroupPlayerScore } => {
        const getPlayerScoreApi =
          type === 'single'
            ? this.getMatchPlayerScore
            : this.getTeamMatchPlayerScore;
        const [homePlayerScoreInfo, awayPlayerScoreInfo] =
          getPlayerScoreApi.call(this, match as MatchInfo, group.id);
        const homePlayerScoreInfoId = homePlayerScoreInfo.playerId;
        total[homePlayerScoreInfoId] = total[homePlayerScoreInfoId] || {};
        this.addObject(total[homePlayerScoreInfoId], homePlayerScoreInfo);
        const awayPlayerScoreInfoId = awayPlayerScoreInfo.playerId;
        total[awayPlayerScoreInfoId] = total[awayPlayerScoreInfoId] || {};
        this.addObject(total[awayPlayerScoreInfoId], awayPlayerScoreInfo);
        return total;
      },
      {},
    );
    logger.info(
      `end getMatchScore type: ${type} groupId: ${group.id} playerScoreInfo: ${Object.values(playerScoreInfo).length}`,
    );
    const sortedPlayerScore = this.sortPlayerScore2(
      Object.values(playerScoreInfo),
    );
    return [...sortedPlayerScore].map((playerScore, index) => {
      playerScore.ranking = index + 1;
      return playerScore;
    });
  },

  getMatchPlayerScore(
    matchInfo: MatchInfo,
    groupId: number,
  ): [GroupPlayerScore, GroupPlayerScore] {
    const {
      winnerId,
      homePlayerId,
      awayPlayerId,
      games,
      homePlayer,
      awayPlayer,
      // subMatchId,
    } = matchInfo;
    if (!winnerId) {
      return [
        {
          ...initGroupPlayerScore,
          playerId: homePlayerId,
          groupId: groupId,
          player: homePlayer,
        },
        {
          ...initGroupPlayerScore,
          playerId: awayPlayerId,
          groupId: groupId,
          player: awayPlayer,
        },
      ];
    }
    // const isSubMatch = subMatchId !== undefined;
    let homePlayerEliminationPosition = null;
    let awayPlayerEliminationPosition = null;
    const isHomePlayerWin = winnerId === homePlayerId;
    const isAwayPlayerWin = winnerId === awayPlayerId;
    if (
      matchInfo.rangeMax &&
      matchInfo.rangeMin &&
      matchInfo.rangeMax - matchInfo.rangeMin === 1
    ) {
      homePlayerEliminationPosition = isHomePlayerWin
        ? matchInfo.rangeMin
        : matchInfo.rangeMax;
      awayPlayerEliminationPosition = isAwayPlayerWin
        ? matchInfo.rangeMin
        : matchInfo.rangeMax;
    }

    const homePlayerScoreInfo: GroupPlayerScore = {
      playerId: homePlayerId,
      player: homePlayer,
      groupId: groupId,
      // registrationIndex: matchInfo.homePlayer.registrationIndex,
      winMatchCount: homePlayerId === winnerId ? 1 : 0,
      loseMatchCount: homePlayerId !== winnerId ? 1 : 0,
      winGameCount: games.filter((game) => game.winnerId === game.homePlayerId)
        .length,
      loseGameCount: games.filter((game) => game.winnerId !== game.homePlayerId)
        .length,
      winRallyCount: games.reduce((acc, game) => {
        const lastProgress = (game as GameInfoV2)?.lastProgress || {};
        const winRally =
          lastProgress?.data.find((item) => item.id === game.homePlayerId)
            ?.score || 0;
        return acc + winRally;
      }, 0),
      loseRallyCount: games.reduce((acc, game) => {
        const lastProgress = (game as GameInfoV2)?.lastProgress || {};
        const loseRally =
          lastProgress?.data.find((item) => item.id === game.awayPlayerId)
            ?.score || 0;
        return acc + loseRally;
      }, 0),
      eliminationPosition: homePlayerEliminationPosition,
      defeat: isHomePlayerWin && [awayPlayerId],
      // winTeamMatchCount: isHomePlayerWin && isSubMatch ? 1 : 0,
      // loseTeamMatchCount: isHomePlayerWin && isSubMatch ? 0 : 1,
    };
    const awayPlayerScoreInfo: GroupPlayerScore = {
      playerId: awayPlayerId,
      player: awayPlayer,
      groupId: groupId,
      // registrationIndex: matchInfo.awayPlayer.registrationIndex,
      winMatchCount: awayPlayerId === winnerId ? 1 : 0,
      loseMatchCount: awayPlayerId !== winnerId ? 1 : 0,
      winGameCount: games.filter((game) => game.winnerId === game.awayPlayerId)
        .length,
      loseGameCount: games.filter((game) => game.winnerId !== game.awayPlayerId)
        .length,
      winRallyCount: games.reduce((acc, game) => {
        const lastProgress = (game as GameInfoV2)?.lastProgress || {};
        const winRally =
          lastProgress?.data.find((item) => item.id === game.awayPlayerId)
            ?.score || 0;
        return acc + winRally;
      }, 0),
      loseRallyCount: games.reduce((acc, game) => {
        const lastProgress = (game as GameInfoV2)?.lastProgress || {};
        const loseRally =
          lastProgress?.data.find((item) => item.id === game.homePlayerId)
            ?.score || 0;
        return acc + loseRally;
      }, 0),
      eliminationPosition: awayPlayerEliminationPosition,
      defeat: isAwayPlayerWin && [homePlayerId],
      // winTeamMatchCount: isAwayPlayerWin && isSubMatch ? 1 : 0,
      // loseTeamMatchCount: isAwayPlayerWin && isSubMatch ? 0 : 1,
    };

    return [homePlayerScoreInfo, awayPlayerScoreInfo];
  },
  addObject(obj1 = {}, obj2 = {}) {
    return Object.keys(obj2).reduce((acc, key) => {
      if (
        [
          'winTeamMatchCount',
          'loseTeamMatchCount',
          'winMatchCount',
          'loseMatchCount',
          'winGameCount',
          'loseGameCount',
          'winRallyCount',
          'loseRallyCount',
        ].includes(key)
      ) {
        acc[key] = (obj1[key] || 0) + (obj2[key] || 0);
      } else if (key === 'defeat') {
        // 如果是defeat 字段，需要合并数组，记录该人击败的所有人
        acc[key] = [...(obj1[key] || []), ...(obj2[key] || [])];
      } else {
        acc[key] = obj2[key];
      }
      return acc;
    }, obj1);
  },
  getTeamMatchPlayerScore(
    matchInfo: MatchInfo,
    groupId: number,
  ): [GroupPlayerScore, GroupPlayerScore] {
    const {
      winnerId,
      subMatchInfos,
      homePlayerId,
      awayPlayerId,
      homePlayer,
      awayPlayer,
      homePlayerRally,
      awayPlayerRally,
    } = matchInfo;
    if (!winnerId) {
      return [
        { ...initGroupPlayerScore, playerId: homePlayerId, groupId: groupId },
        { ...initGroupPlayerScore, playerId: awayPlayerId, groupId: groupId },
      ];
    }
    const [subMatchHomeScoreInfo, subMatchAwayScoreInfo] = subMatchInfos.reduce(
      (total, subMatchInfo) => {
        const _winnerId =
          subMatchInfo.winnerId === subMatchInfo.homePlayerId // 这里计算当场胜者所在团队的id
            ? homePlayerId
            : awayPlayerId;
        const [homePlayerScoreInfo, awayPlayerScoreInfo] =
          this.getMatchPlayerScore(
            // 这里为了方便复用，将具体player的名称换成的所在队的名称
            {
              ...subMatchInfo,
              homePlayer,
              awayPlayer,
              homePlayerId,
              awayPlayerId,
              winnerId: _winnerId,
            } as any,
            groupId,
          );
        return [
          this.addObject(total[0], homePlayerScoreInfo),
          this.addObject(total[1], awayPlayerScoreInfo),
        ];
      },
      [{}, {}],
    );
    subMatchHomeScoreInfo.winTeamMatchCount =
      homePlayerRally > awayPlayerRally ? 1 : 0;
    subMatchHomeScoreInfo.loseTeamMatchCount =
      awayPlayerRally > homePlayerRally ? 1 : 0;
    subMatchAwayScoreInfo.winTeamMatchCount =
      awayPlayerRally > homePlayerRally ? 1 : 0;
    subMatchAwayScoreInfo.loseTeamMatchCount =
      homePlayerRally > awayPlayerRally ? 1 : 0;
    return [subMatchHomeScoreInfo as any, subMatchAwayScoreInfo as any];
  },
  // sortPlayerScore(
  //   groupPlayerScores: GroupPlayerScore[],
  // ): Array<GroupPlayerScore> {
  //   return groupPlayerScores.sort((a, b) => {
  //     // const res =
  //     //   !b.player || b.player.isByePlayer
  //     //     ? -1 // 轮空或者没有指定选手，往后排
  //     //     : (b.eliminationPosition || 0) - (a.eliminationPosition || 0) > 0 ||
  //     //         b.winMatchCount - a.winMatchCount > 0 ||
  //     //         b.winGameCount - a.winGameCount > 0 ||
  //     //         b.winRallyCount -
  //     //           b.loseRallyCount -
  //     //           (a.winRallyCount - a.loseRallyCount) >
  //     //           0 || // 计算净得分
  //     //         b.defeat?.includes(a.playerId)
  //     //       ? 1
  //     //       : -1; // 计算b是否击败过a
  //     if (!b.player || b.player.isByePlayer) {
  //       return -1;
  //     } else if (!a.player || a.player.isByePlayer) {
  //       return 1;
  //     }
  //     if (b.winTeamMatchCount - a.winTeamMatchCount > 0) {
  //       // 比较团赛胜局
  //       return 1;
  //     } else if (b.winTeamMatchCount - a.winTeamMatchCount < 0) {
  //       return -1;
  //     }
  //     if (b.winMatchCount - a.winMatchCount > 0) {
  //       // 比较胜场
  //       return 1;
  //     } else if (b.winMatchCount - a.winMatchCount < 0) {
  //       return -1;
  //     }
  //     if (b.winGameCount - a.winGameCount > 0) {
  //       // 比较胜局
  //       return 1;
  //     } else if (b.winGameCount - a.winGameCount < 0) {
  //       return -1;
  //     }
  //     if (
  //       // 比较净胜分
  //       b.winRallyCount -
  //         b.loseRallyCount -
  //         (a.winRallyCount - a.loseRallyCount) >
  //       0
  //     ) {
  //       // 比较胜 rally
  //       return 1;
  //     } else if (
  //       b.winRallyCount -
  //         b.loseRallyCount -
  //         (a.winRallyCount - a.loseRallyCount) <
  //       0
  //     ) {
  //       return -1;
  //     }
  //     if (b.defeat?.includes(a.playerId)) {
  //       return 1;
  //     } else {
  //       return 0;
  //     }
  //   });
  // },
  // ... existing code ...
  sortPlayerScore2(
    groupPlayerScores: GroupPlayerScore[],
    compareField: string = 'winTeamMatchCount',
  ): Array<GroupPlayerScore> {
    const sortFieldOrder = [
      'winTeamMatchCount',
      'winMatchCount',
      'winGameCount',
      'netRally',
    ];

    // 过滤出非轮空选手和轮空选手
    const nonByePlayers = groupPlayerScores.filter(
      (p) => p.player && !p.player.isByePlayer,
    );
    const byePlayers = groupPlayerScores.filter(
      (p) => !p.player || p.player.isByePlayer,
    );

    // 对比两个人的对战成绩，决定胜局
    const compare2Players = (
      a: GroupPlayerScore,
      b: GroupPlayerScore,
    ): GroupPlayerScore[] => {
      // 先比较给定字段的值大小
      const scoreA = getScore(a, compareField);
      const scoreB = getScore(b, compareField);

      if (scoreA > scoreB) {
        return [a, b]; // a的分数更高，a在前
      } else if (scoreA < scoreB) {
        return [b, a]; // b的分数更高，b在前
      }

      // 如果给定字段的值相同，再比较两个人的胜负场
      if (a.defeat?.includes(b.playerId)) {
        return [a, b]; // a击败过b，a在前
      } else if (b.defeat?.includes(a.playerId)) {
        return [b, a]; // b击败过a，b在前
      }

      // 如果没有直接对战记录，保持原顺序
      return [a, b];
    };

    // 对比大于两个人的对战成绩，比较compareField字段决定胜局，如果存在平局，则继续比较下一个字段，直到决出胜负
    const compareMoreThan2Players = (
      players: GroupPlayerScore[],
      currentCompareField: string,
    ): GroupPlayerScore[] => {
      // 按当前字段排序
      const sortedByCurrentField = [...players].sort((a, b) => {
        if (currentCompareField === 'netRally') {
          const netRallyA = (a.winRallyCount || 0) - (a.loseRallyCount || 0);
          const netRallyB = (b.winRallyCount || 0) - (b.loseRallyCount || 0);
          return netRallyB - netRallyA; // 降序排列
        } else {
          const scoreA = (a as any)[currentCompareField] || 0;
          const scoreB = (b as any)[currentCompareField] || 0;
          return scoreB - scoreA; // 降序排列
        }
      });

      // 检查是否有并列选手，如果有则递归比较
      const result: GroupPlayerScore[] = [];
      let i = 0;

      while (i < sortedByCurrentField.length) {
        // 找到当前分数相同的所有选手
        const currentScore = getScore(
          sortedByCurrentField[i],
          currentCompareField,
        );
        let j = i;
        while (
          j < sortedByCurrentField.length &&
          getScore(sortedByCurrentField[j], currentCompareField) ===
            currentScore
        ) {
          j++;
        }

        const tiedPlayers = sortedByCurrentField.slice(i, j);

        // 如果只有一个选手或者已经是最后一个比较字段，则直接添加
        const currentFieldIndex = sortFieldOrder.indexOf(currentCompareField);
        if (
          tiedPlayers.length === 1 ||
          currentFieldIndex >= sortFieldOrder.length - 1
        ) {
          result.push(...tiedPlayers);
        } else {
          // 否则递归调用，使用下一个字段进行比较
          const nextField = sortFieldOrder[currentFieldIndex + 1];
          const sortedTiedPlayers = this.sortPlayerScore2(
            tiedPlayers,
            nextField,
          );
          result.push(...sortedTiedPlayers);
        }

        i = j;
      }

      return result;
    };

    // 辅助函数：获取选手在指定字段的分数
    const getScore = (player: GroupPlayerScore, field: string): number => {
      if (field === 'netRally') {
        return (player.winRallyCount || 0) - (player.loseRallyCount || 0);
      }
      return (player as any)[field] || 0;
    };

    if (nonByePlayers.length <= 1) {
      // 如果非轮空选手少于等于1人，直接返回所有选手，轮空选手放在最后
      return [...nonByePlayers, ...byePlayers];
    } else if (nonByePlayers.length === 2) {
      // 如果非轮空选手正好2人，使用compare2Players比较
      const sortedNonByePlayers = compare2Players(
        nonByePlayers[0],
        nonByePlayers[1],
      );
      return [...sortedNonByePlayers, ...byePlayers];
    } else {
      // 如果非轮空选手多于2人，使用compareMoreThan2Players比较
      const sortedNonByePlayers = compareMoreThan2Players(
        nonByePlayers,
        compareField,
      );
      return [...sortedNonByePlayers, ...byePlayers];
    }
  },
  // ... existing code ...
};
